package com.my.study.common.security.remember;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.security.web.authentication.rememberme.PersistentRememberMeToken;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 基于redis的记住我令牌持久化实现类
 * 
 * @author yidujun
 * @date 2022/8/5 15:40
 */
@Slf4j
@Component("customRedisPersistentTokenRepository")
public class CustomRedisPersistentTokenRepository implements PersistentTokenRepository {
    
    private static final String PREFIX_USER_NAME = "spring:security:rememberMe:username:";
    private static final String PREFIX_SERIES = "spring:security:rememberMe:series:";
    
    @Resource
    private RedissonClient redissonClient;
    
    @Override
    public void createNewToken(PersistentRememberMeToken token) {
        String series = token.getSeries();
        String username = token.getUsername();
        PersistentRememberMeToken persistentRememberMeToken = getTokenForSeries(series);
        if (null != persistentRememberMeToken) {
            log.warn("清除之前的remember me的token记录");
            removeUserTokens(username);
        }
        putBySeries(token);
        putByUserName(token);
    }

    @Override
    public void updateToken(String series, String tokenValue, Date lastUsed) {
        PersistentRememberMeToken tokenForSeries = getTokenForSeries(series);
        PersistentRememberMeToken persistentRememberMeToken = new PersistentRememberMeToken(tokenForSeries.getUsername(), 
                series, tokenValue, lastUsed);
        putBySeries(persistentRememberMeToken);
        putByUserName(persistentRememberMeToken);
    }

    @Override
    public PersistentRememberMeToken getTokenForSeries(String seriesId) {
        Object obj = redissonClient.getBucket(PREFIX_SERIES + seriesId).get();
        if (obj != null) {
            CustomPersistentRememberMeToken token =  (CustomPersistentRememberMeToken) obj;
            return token.toToken(token);
        }
        return null;
    }

    @Override
    public void removeUserTokens(String username) {
        RBucket<Object> userNameBucket = redissonClient.getBucket(PREFIX_USER_NAME + username);
        if (null != userNameBucket) {
            String series = (String) userNameBucket.get();
            redissonClient.getBucket(username).delete();
            redissonClient.getBucket(PREFIX_SERIES + series).delete();
        }
    }


    private void putBySeries(PersistentRememberMeToken token) {
        CustomPersistentRememberMeToken newToken = new CustomPersistentRememberMeToken(token);
        redissonClient.getBucket(PREFIX_SERIES + token.getSeries()).set(newToken, 30, TimeUnit.DAYS);
    }

    private void putByUserName(PersistentRememberMeToken token) {
        String username = token.getUsername();
        redissonClient.getBucket(PREFIX_USER_NAME + username).set(token.getSeries(), 30, TimeUnit.DAYS);
    }
    
}
